from flask import current_app
from flask import request, jsonify
from flask import session
from sqlalchemy.sql.functions import user

from info import db
from info.response import RET
from . import news_blueprint
from info .utils.common import login_wrapps
from info.models import News, User, Comment, CommentLike
from flask import render_template,g
# 定义试图,并切装饰蓝图
@news_blueprint.route('/<int:news_id>')
@login_wrapps
def detail(news_id):
    # 引入新闻类,查询新闻
    news = News.query.get_or_404(news_id)
    #点击量,使用浏览量的字段进行自增
    news.clicks += 1
    #吧每次的点击量进行保存到数据库
    db.session.commit()

    #点击量排行
    #引入,utils模块中的点击量字段
    from info.utils.common import get_click_list
    news_list2 = get_click_list()


    #查询当前新闻是否被当前用户收藏,通过collection_news关系查询的数据
    #并不是通过查询语句实现的
    if g.user and news in g.user.collection_news:
        is_collected = True
    else:
        is_collected = False
    #查询当前新闻所有的评论信息
    # 通过新闻表中的comments关系属性进行精确查询,再吧查询到的数据进行精确查询
    comment_list1 = news.comments.filter_by(parent_id = None).order_by(Comment.id.desc())
    #吧查询到的数据,遍历程单个的对象,然后吧遍历出来的对象调用to_dict这个方法
    comment_list2 = [comment.to_dict() for comment in comment_list1]

    #查询当前登的用户是否对某个评论点赞
    if g.user:
        #获取当前新闻所有评论的编号
        comment_ids = [comment.id for comment in comment_list1]
        #查询点赞表:当前新闻的评论,当前用户点赞过的数据

        likes = CommentLike.query.filter_by(user_id = g.user.id).filter(CommentLike.comment_id.in_(comment_ids))
        # 获取点赞的ID
        likes_ids = [like.comment_id for like in likes]

        for comment in comment_list2:
            comment['is_like'] = comment.get('id') in likes_ids
    data = {
        'news' : news,
        'user' : g.user.to_login_dict() if g.user else None,
        'news_list' : news_list2,
        'is_collected' : is_collected,
        'comment_list' : comment_list2,
        'author' : news.author.to_dict()
    }

    return render_template('news/detail.html',data = data)


@news_blueprint.route('/news_collect', methods=['POST'])
@login_wrapps
def news_collect():
    '''向用户收藏新闻的中间表中添加、删除数据'''
    # 1.接收
    #接收用户的ID
    news_id = request.json.get('news_id')
    #接收用户的操作信息
    action = request.json.get('action')

    # 2.验证
    # 2.1非空,如果账号是空的就代表没登陆
    if not all([news_id, action]):
        return jsonify(errno=RET.NODATA, errmsg='数据不完整')
    # 2.2登录,因为验证了登陆 才能收藏
    if g.user is None:
        return jsonify(errno=RET.LOGINERR, errmsg='用户未登录')
    # 2.3查询新闻对象
    try:#因为,要从数据库中查询所以要加捕获异常
        news = News.query.get(news_id)
    except Exception as e:
        # 对于出现错误，需要开发人员或运维人员解决，则这种错误存入日志，如连接mysql、redis
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库连接失败')
    # 2.4是否有效的news_id
    if news is None:
        return jsonify(errno=RET.DATAERR, errmsg='无效的新闻编号')
    # 2.5action的值是否有效
    if action not in ('collect', 'cancel_collect'):
        return jsonify(errno=RET.DATAERR, errmsg='无效的操作')

    # 3.处理:向中间表中添加或删除数据
    user = g.user
    if action == 'collect':
        # 收藏
        if news not in user.collection_news:
            user.collection_news.append(news)
            # db.session.add(对象)===>insert into
            # insert into ...
    else:
        # 取消收藏
        if news in user.collection_news:
            user.collection_news.remove(news)
    try:
        db.session.commit()
        # 执行insert语句
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库连接失败')

    # 4.响应
    return jsonify(errno=RET.OK, errmsg='')



@news_blueprint.route('/comment_add', methods=['POST'])
@login_wrapps
def comment_add():
    '''
    添加评论、回复
    评论：无parent_id
    回复：有parent_id
    '''
    # 1.接收
    news_id = request.json.get('news_id')
    msg = request.json.get('comment')
    parent_id = request.json.get('parent_id')

    # 2.验证
    # 2.1非空
    if not all([news_id, msg]):
        return jsonify(errno=RET.NODATA, errmsg='数据不完整')
    # 2.2验证新闻有效
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.err(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库连接失败')
    if news is None:
        return jsonify(errno=RET.DATAERR, errmsg='新闻编号无效')
    # 2.3验证用户是否登录
    if g.user is None:
        return jsonify(errno=RET.LOGINERR, errmsg='请先登录')

    # 3.处理：创建Comemnt对象，保存到数据库
    comment = Comment()
    comment.user_id = g.user.id
    comment.news_id = int(news_id)
    comment.content = msg
    print(comment)
    # 区分是评论还是回复
    if parent_id:
        comment.parent_id = int(parent_id)
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库连接失败')

    # 4.响应
    return jsonify(errno=RET.OK, errmsg='', data=comment.to_dict())




# 点赞,功能

# 定义点赞试图,装饰蓝图,并且调用定义好的登陆装饰器
@news_blueprint.route('/comment_like',methods = ["POST"])
@login_wrapps
def comment_like():
# 1,接收用户操作的数据
    news_id = request.json.get('news_id')#用户ID
    comment_id = request.json.get('comment_id')#点赞ID
    action = request.json.get('action')#用户操作的行为
# 2,验证接的数据是否为空
    if not all([news_id,comment_id,action]):
        return jsonify(errno = RET.NODATA,errmsg = '数据不完整')

    #2.2 验证用户是否登陆,登陆了才可以点赞
    if g.user is None:
        return jsonify(errno = RET.LOGINERR,errmsg = '用户未登录')
    #2.3查找新闻,只有找到新闻才可以取点赞,查找新闻对象,要从数据库查找所以要用捕获异常
    try: #查找新闻要接收新闻类中查出的数据
        news = News.query.get(news_id)
    except Exception as e:
        #吧错误信息输出到日志里
        current_app.logger.error(e)
        return jsonify(errno = RET.DBERR,errmsg = '数据库链接失败')
    # 查询是否是有效的news_id
    if news_id is None:
        return jsonify(errno = RET.DATAERR,errmsg = '无效的新闻编号')
    #查询action是不是有效的
    if action is None:
        return jsonify(errno = RET.DATAERR,errmsg = '无效的操作')
#3,处理逻辑/向CommentLike表中添加数据
    # 1创建变量接收从用户里的id
    user_id = g.user.id
    # 2然后接收从Comment中查找出来的点赞ID
    comment = Comment.query.get(comment_id)
    #验证用户的操作行为判断是否点赞
    if action =='add':#如果操作是'add'就点赞
    #3 点赞/创建点赞对象
        like =CommentLike()
        #给点赞对象赋值,因为浏览器的请求都是字符串所以要转换程整形
        like.comment_id =int(comment_id)
        # 点赞用户的ID = 新闻用户ID
        like.user_id = user_id
        try: # 因为要把点赞的数据,添加到数据库所以用捕获异常
            #给当前的新闻设定点赞自增
            comment.like_count +=1
            db.session.add (like)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno = RET.DBERR,errmsg = '连接数据库失败')
        #取消点赞
    else:#创建点赞对象,精确查找,当前的点赞ID是否还是当前ID当前的用户ID还是当前用户ID表示没变化
        like = CommentLike.query.filter_by(comment_id = comment_id,user_id = user_id).first()

        try:#取消点赞,就是从点赞表中删除点赞记录所以用递减
            comment.like_count -=1
            db.session.delete(like)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno = RET.DBERR,errmsg = '数据库链接失败')

#4响应,吧做好得逻辑处理返回,
    return jsonify(errno = RET.OK,errmsg = '')


@news_blueprint.route('/followed_user', methods=['POST'])
@login_wrapps
def followed_user():
    #1.接收
        #接受用户的操作和作者DI
    author_id=request.json.get('user_id')
    action=request.json.get('action')

    #2.验证：与收藏代码类似
    if not all([author_id,action]):
        return jsonify(errno=RET.NODATA,errmsg='数据不完整')
    if action not in ('follow','unfollow'):
        return jsonify(errno=RET.DATAERR,errmsg='操作无效')
    if g.user is None:
        return jsonify(errno=RET.LOGINERR,errmsg='请先登录')
    try:
        author=User.query.get(author_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='数据库连接失败')
    if author is None:
        return jsonify(errno=RET.DATAERR,errmsg='作者编号无效')

    #3.处理
    user=g.user
    if action=='follow':
        if author not in user.authors:
            user.authors.append(author)
    else:
        if author in user.authors:
            user.authors.remove(author)

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='关注/取消关注失败')

    #4.响应
    return jsonify(errno=RET.OK,errmsg='')








